如何处理缺失值?这一篇搞定!
本文作者:寇晓璇,中南财经政法大学统计与数学学院
本文编辑:杨婉清
技术总编:陈 鼎
Stata&Python云端课程来啦!
为了感谢大家长久以来的支持和信任,爬虫俱乐部为大家送福利啦!!!Stata&Python特惠课程双双上线腾讯课堂~原价2400元的Python编程培训课程,现在仅需100元,详情请查看推文《Python云端课程福利大放送!0基础也能学~》。关于Stata,爬虫俱乐部推出了系列课程,内容包括字符串函数、正则表达式、爬虫专题和文本分析,可以随心搭配,价格美丽,物超所值,更多信息可查看Stata系列推文《与春天有个约会,爬虫俱乐部重磅推出正则表达式网络课程!》、《与春天有个约会,爬虫俱乐部重磅推出基本字符串函数网络课程》等。变的是价格,不变的是课程质量和答疑服务。对报名有任何疑问欢迎在公众号后台和腾讯课堂留言哦!
数据缺失的原因
在各种数据库中,属性值缺失的情况时有发生。造成数据缺失的原因是多方面的,小编认为主要可以分为以下两种:
客观原因:有些信息暂时无法提取,如在短时间无法获得的临床检验结果;某些属性值本身不存在,如未婚者的配偶姓名;获取某些信息的代价太大;系统实时性能要求较高,要求在得到这些信息前做出决策。
主观原因:数据在输入时由于人为因素被遗漏;被认为是无关紧要的信息。
总之,对于造成缺失值的原因,我们要明确一点:是因为工作人员疏忽造成的,还是数据本身就无法提取。只有明确数据缺失的原因,方能对症下药。
数据缺失的类型
明确两个概念:数据集中不含缺失值的变量称为`完全变量`,数据集中含有缺失值的变量称为`不完全变量`。从缺失的分布来看可以将缺失分为`完全随机缺失`,`随机缺失`和`完全非随机缺失`。
完全随机缺失:指数据的缺失是完全随机的,不依赖于任何不完全变量或完全变量,不影响样本的无偏性。如家庭地址缺失。
随机缺失:指数据的缺失不是完全随机的,即该类数据的缺失依赖于其他完全变量。如财务数据缺失,其与企业规模有关。
非随机缺失:指的是数据的缺失与不完全变量自身的取值有关。如高收入人群不愿意提供家庭收入。
数据缺失的类型关乎我们如何去处理缺失数据。对于后两种情况,直接删除记录是不合适的。随机缺失可以通过已知变量对缺失值进行估计,而非随机缺失的非随机性目前还没有很好的解决办法。
数据缺失的处理方法
啰嗦了这么多,那么该如何去处理缺失数据?数据处理的方法又有哪些呢?
处理不完备的数据集主要分为以下三类:
删除记录
数据填充
不处理
1
.删除记录
该方法方便快捷,简单粗暴。但其牺牲了大量数据,可能会丢失许多隐藏重要信息,尤其是在缺失数据占比较大时,可能会直接导致数据的分布发生变化,导致得出错误的结论。该方法适用于缺失数据相对样本数据来说很少的情况。可以使用`pandas`中的`dropna`直接删除有缺失值的特征。
# 直接删除含有缺失值的行
df.dropna(how='any',axis = 0)
df.dropna() # 等价形式
# 直接删除含有缺失值的列
df.dropna(how='any',axis = 1)
# 只删除全是缺失值的行
df.dropna(how = 'all')
2
.数据填充
该方法是用一定值去填充空值,进而使数据完备。通常有以下三大类填充方法,分别为`替换缺失值`、`拟合缺失值`和`虚拟变量`。
(1)均值填充。将所有属性划分为数值属性和非数值属性,若空值是定量的,则按该属性在其他所有对象取值的`均值`或`中位数`来填充;若空值是定性的,则用该属性在其他所有对象的众数来填充。此方法简单不够精准,可能会改变特征原有分布。
# 使用var1的均值/中位数对 NA进行填充
df['var1'].fillna(df['var1'].mean())
df['var1'].fillna(df['var1'].median())
(2)热卡填充。它的思想十分简单,即找一个与缺失值对象最相近的对象来进行填充。通常会找到不止一个相似对象,在所有匹配对象中没有最好的,而是从中随机挑选一个作为填充值。不同的问题可能会选用不同的标准来对相似进行判定,但定义相似标准较难,主观因素太多。
(3)K最近距离邻法。先根据`欧氏距离`或`相关分析`来确定距离具有缺失数据样本最近的K个样本,将这K个值加权平均来估计该样本的缺失数据。
(4)使用所有可能的值填充。该方法是用空缺属性值的所有可能的属性取值来填充,能得到较好的补齐效果。但当数据量较大、遗漏的属性值较多时,其计算代价较大。
(1)回归。基于完整的数据集,建立回归方程。对包含空值的对象,将已知属性值代入方程来估计未知属性值,以此估计值来进行填充。但缺点是当变量不是线性相关或预测变量高度相关时会导致有偏差的估计。(2)期望值最大化方法。这里利用到了EM算法,分为E步和M步两个步骤,E步在给定完全数据和前一次迭代所得到的参数估计的情况下计算完全数据对应的对数似然函数的条件期望,M步是用极大化对数似然函数以确定参数的值,并用于下一步的迭代。算法在E步和M步之间不断迭代直至收敛。但该方法的缺点是可能会陷入局部极值,而且收敛速度不快,计算较为复杂。(3)多重插补方法。该方法来源于贝叶斯估计,主要分为以下三个步骤:第一,为每个空值产生一套可能的填补值,这些值反映了无响应模型的不确定性,每个值都被用来填补数据集中的缺失值,产生若干个完整数据集合;第二,每个填补数据集合都用针对完整数据集的统计方法进行统计分析;第三,对来自各个填补数据集的结果进行综合,产生最终的统计推断,这一推断考虑到了由于数据填补而产生的不确定性。该方法将空缺值视为随机样本,这样计算出来的统计推断可能受到空缺值的不确定性的影响。该方法的缺点是计算复杂。(4)随机森林。这是很多竞赛中大家经常使用的一种办法,同样是将缺失值作为目标变量。某案例代码如下:
# 导入随机森林模块
from sklearn.ensemble import RandomForestRegressor
# 定义函数
def set_missing_ages(df):
#把数值型特征都放到随机森林里面去
age_df=df[['Age','Fare','Parch','SibSp','Pclass']]
known_age = age_df[age_df.Age.notnull()].as_matrix()
unknown_age = age_df[age_df.Age.isnull()].as_matrix()
y=known_age[:,0] # y是年龄,第一列数据
x=known_age[:,1:] # x是特征属性值,后面几列
rfr=RandomForestRegressor(random_state=0,n_estimators=2000,n_jobs=-1)
#根据已有数据去拟合随机森林模型
rfr.fit(x,y)
#预测缺失值
predictedAges = rfr.predict(unknown_age[:,1:])
#填补缺失值
df.loc[(df.Age.isnull()),'Age'] = predictedAges
return df,rfr
虚拟变量是缺失值的一种衍生变量。具体做法是通过判断特征值是否有缺失值来定义一个新的二分类变量。比如,特征为A含有缺失值,我们衍生出一个新的特征B,如果A中特征值有缺失,那么相应的B中的值为1,如果A中特征值没有缺失,那么相应的B中的值为0。某案例代码如下:
# 复制该列数据到 CabinCat
data_train['CabinCat'] = data_train['Cabin'].copy()
# 设置虚拟变量
data_train.loc[ (data_train.CabinCat.notnull()), 'CabinCat' ] = "No"
data_train.loc[ (data_train.CabinCat.isnull()), 'CabinCat' ] = "Yes"
# 查看
data_train[['Cabin','CabinCat']].head(10)
前两类方法仅仅是用我们的主观估计值填补未知值,我们或多或少地改变了原始的数据集。而且,对空值不正确的填充往往将新的噪声引入数据中,使挖掘任务产生错误的结果。因此,在许多情况下,我们还是希望在保持原始信息不发生变化的前提下对信息系统进行处理。另外,有一些模型本身就足以应对具有缺失值的数据,此时无需对数据进行处理,比如`XGBoost`等高级模型。
PART 04实证演练
以下通过一个案例来简单学习一下缺失值处理常用的几种方法。
import pandas as pd
# 导入数据集
df = pd.read_csv('Data.csv',encoding = 'gbk',na_values='Na') #为空数据赋值
df.dtypes
# 对里程数进行处理
def f(x):
if '$' in str(x):
x = str(x).strip('$')
x = str(x).replace(',','')
else:
x = str(x).replace(',','')
return float(x)
df['Mileage'] = df['Mileage'].apply(f)
# 显示各变量缺失比例
df.apply(lambda x: sum(x.isnull())/len(x),axis= 0)
# 直接删除法——删除'Condition','Price','Mileage'三个变量含有缺失值的行
df.dropna(axis = 0,how='any',subset=['Condition','Price','Mileage'])
# 里程用均值填补
df.Mileage.fillna(df.Mileage.mean())
# 用众数填补
df.Exterior_Color.fillna(df.Exterior_Color.mode()[0])
# 婚姻状况使用众数填补,年龄使用均值填补,农户家庭人数使用中位数填补
df.fillna(value = {'Exterior_Color':df.Exterior_Color.mode()[0],'Mileage':df.Mileage.mean()})
# 虚拟变量法
df['Watch_Count1'] = df['Watch_Count'].copy()
df.loc[ (df.Watch_Count.notnull()), 'Watch_Count1' ] = "No"
df.loc[ (df.Watch_Count.isnull()), 'Watch_Count1' ] = "Yes"
df[['Watch_Count','Watch_Count1']].head(10)
注:数据可以通过后台回复“缺失值”获取。
PART 05小结
以下为本文的思维框架图:
总的来说,大部分数据挖掘的预处理都会使用比较方便的方法来处理缺失值,比如均值法,但是效果上并一定好,因此还是需要根据不同的需要选择合适的方法,并没有万能方法。具体方法还是要从多方面考虑。
以上就是我们今天的全部内容了,希望在数据清洗方面可以帮助到大家。
最后,我们为大家揭秘雪球网(https://xueqiu.com/)最新所展示的沪深证券和港股关注人数增长Top10。
对我们的推文累计打赏超过1000元,我们即可给您开具发票,发票类别为“咨询费”。用心做事,不负您的支持!
善用dataex命令,高效沟通你我他
大数据下的大学分数线排行榜,快来围观!
《觉醒年代》—带你回到百年前
用Stata画的三维图很奇怪怎么办?
如何随机生成满足特定数据特征的新变量?
爬取无法翻页网页——自然科学基金项目及可视化
爬取京东评论数据进行情感分类
Stata与音乐之间的酷炫连接
这些年,爬虫俱乐部走出的博士们!看这里,近五年各校高被引论文上榜名单!
高校经管类核心期刊发文排行榜
疯狂的科研创新加速器——Stata!
可盐可甜,“粽”有所爱,快来pick你最爱的粽子吧!
好玩有趣的手绘图形库——cutecharts
爬虫实战|摩尔庄园微博话题讨论
一季度财报出炉,哪些公司最烧钱?
一季度财报出炉,哪些公司最赚钱?
技能篇 | 图片合并大法
批量空气质量数据文件合并分析
Stata17之日期时间新功能
Stata17之Lasso新功能
爱奇艺视频弹幕爬取之《小舍得》 数据可视化利器——Matplotlib从第七次人口普查看中国人口变化|Stata与Python交互绘图
200万投资者关注!!哪家公司这么牛?
带你领略一天天气之变化
利用pyecharts看微博粉丝地区分布
零值太多怎么办?解锁Stata17新命令ziologit
关于我们
微信公众号“Stata and Python数据分析”分享实用的Stata、Python等软件的数据处理知识,欢迎转载、打赏。我们是由李春涛教授领导下的研究生及本科生组成的大数据处理和分析团队。
此外,欢迎大家踊跃投稿,介绍一些关于Stata和Python的数据处理和分析技巧。
投稿邮箱:statatraining@163.com投稿要求:
1)必须原创,禁止抄袭;
2)必须准确,详细,有例子,有截图;
注意事项:
1)所有投稿都会经过本公众号运营团队成员的审核,审核通过才可录用,一经录用,会在该推文里为作者署名,并有赏金分成。
2)邮件请注明投稿,邮件名称为“投稿+推文名称”。
3)应广大读者要求,现开通有偿问答服务,如果大家遇到有关数据处理、分析等问题,可以在公众号中提出,只需支付少量赏金,我们会在后期的推文里给予解答。